/**
 * Assignment 2 - Pub crawl
 * Authors: Huy Nguyen (3430069)    James Gregory (3288801)
 */
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>

#include "pub.h"

extern int num_delegates;
extern MPI_Comm world_comm;

static int *pub_list;
static void initialize_pub_list(void) {
    pub_list = (int *)malloc(num_delegates * sizeof(int));
    for (int i = 0; i < num_delegates; i++) {
        pub_list[i] = i+1;
    }
}

static void shuffle_pub_list(void) {
    for (size_t i = 0; i < num_delegates - 1; i++) {
        size_t j = i + rand() / (RAND_MAX / (num_delegates - i) + 1);
        int t = pub_list[j];
        pub_list[j] = pub_list[i];
        pub_list[i] = t;
    }
}

static void send_pub_list(void) {
    MPI_Bcast(pub_list, num_delegates, MPI_INT, ROOT, world_comm);
}

static int check_game_state(int *decisions) {
    int decision[3] = {0};
    int game_state = GAME_CONTINUE;
    MPI_Gather(decision, 3, MPI_INT, decisions, 3, MPI_INT, ROOT, world_comm);
    int last_decision_chosen_by_sober = 0;
    int num_of_drunk_delegates = 0;
    for(int i = 1; i <= num_delegates; i++) {
        // delegate not drunk
        if (decisions[i*3+1] >= 0) {             
            if(last_decision_chosen_by_sober 
                && (last_decision_chosen_by_sober != decisions[i*3])
                && (last_decision_chosen_by_sober < BODYGUARD_ID_OFFSET)
                && (decisions[i*3] < BODYGUARD_ID_OFFSET)) {
               game_state = GAME_WON_BY_BODYGUARD;
            }
            last_decision_chosen_by_sober = decisions[i*3];
        }
        if (decisions[i*3+1] < 0) {
            num_of_drunk_delegates++;
            if (num_of_drunk_delegates == num_delegates - 1) {
                game_state = GAME_WON_BY_DELEGATE;
            }
        }
        // bodyguard drunk
        if (decisions[i*3+2] < 0) {             
            game_state = GAME_WON_BY_DELEGATE;
            break;
        }
    }
    return game_state;
}

void game_master(void) {
    initialize_pub_list();
    shuffle_pub_list();
    send_pub_list();
    int game_state = GAME_CONTINUE;
    int *decisions = (int*)malloc(3*(num_delegates+1)*sizeof(int));
    for(int round = 0; round < num_delegates; round++) {
        printf("Round %d -------------------------------------\n", (round+1));
        printf("Pub vote\n");
        MPI_Barrier(world_comm);
        game_state = check_game_state(decisions);
        MPI_Bcast(&game_state, 1, MPI_INT, ROOT, world_comm);
        if(game_state) { break; }
        printf("Wench vote\n");
        MPI_Barrier(world_comm);
        game_state = check_game_state(decisions);
        MPI_Bcast(&game_state, 1, MPI_INT, ROOT, world_comm);
        if(game_state) { break; }
        MPI_Barrier(world_comm);
    }
    
    if (game_state == GAME_WON_BY_BODYGUARD) {
        printf("Game won by bodyguards.\n");
    } else {
        printf("Game won by delegates.\n");
    }       
    free(decisions);
}
